#include<vector>
#include<ctime>
#include<cmath>
#include<string>
#include<fstream>
#include"Util.h"
#include"StringPool.h"
#include"variable.h"
#include"DependencyInstance.h"
#include"KBestParseForest.h"
#include"DependencyPipe2O.h"
using namespace std;

DependencyPipe2O::DependencyPipe2O(ParserOptions *options) : DependencyPipe2OGrandChildren(options){}

DependencyPipe2O::~DependencyPipe2O(){}

void DependencyPipe2O::addExtendedFeatures(DependencyInstance *instance, FeatureVector *fv){
	const int instanceLength = instance->length();
	vector<int> *heads = instance->heads;

	for(int i = 0; i < instanceLength; i++){
		if((*heads)[i] == -1 && i != 0){
			continue;
		}

		// right children
		int prev = i;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		// left children
		prev = i;
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i) {
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		//left features;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				for(int k = i + 1; k < instanceLength; k++){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}

		//right features
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i){
				for(int k = i - 1; k >= 0; k--){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}
	}
}

void DependencyPipe2O::addTripFeatures(DependencyInstance *instance, int par, int ch1, int ch2, FeatureVector *fv){
	vector<string*> *pos = instance->postags;

	bool flag;
	// ch1 is always the closest to par
	string dir = par > ch2 ? "RA" : "LA";

	string par_pos = *(*pos)[par];
	string ch1_pos = ch1 == par ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = (*(*pos)[ch2]);

	string pTrip = par_pos + "_" + ch1_pos + "_" + ch2_pos;
	string tmp = "POS_TRIP=" + pTrip + "_" + dir;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APOS_TRIP=" + pTrip;
	}
	else{
		tmp = "APOS_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	
	vector<string*> *cpos = instance->cpostags;
	string par_cpos = *(*cpos)[par];
	string ch1_cpos = ch1 == par ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = (*(*cpos)[ch2]);
	pTrip = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "CPOS_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ACPOS_TRIP=" + pTrip;
	}
	else{
		tmp = "ACPOS_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	vector<string*> *forms = instance->forms;
	string par_form = *(*forms)[par];
	string ch1_form = ch1 == par ? "STWRD" : *(*forms)[ch1];
	string ch2_form = *(*forms)[ch2];

	pTrip = par_form + "_" + ch1_form + "_" + ch2_form;
	tmp = "FORM_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFORM_TRIP=" + pTrip;
	}
	else{
		tmp = "AFORM_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string par_b = par_pos + "[" + par_form + "]";
	string ch1_b = ch1_pos + "[" + ch1_form + "]";
	string ch2_b = ch2_pos + "[" + ch2_form + "]";

	string par_cb = par_cpos + "[" + par_form + "]";
	string ch1_cb = ch1_cpos + "[" + ch1_form + "]";
	string ch2_cb = ch2_cpos + "[" + ch2_form + "]";

	pTrip = par_b + "_" + ch1_pos + "_" + ch2_pos;
	tmp = "FPOSP_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSP_TRIP=" + pTrip;
	}
	else{
		tmp = "AFPOSP_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pTrip = par_cb + "_" + ch1_cpos + "_" + ch2_cpos;
	tmp = "FCPOSP_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSP_TRIP=" + pTrip;
	}
	else{
		tmp = "AFCPOSP_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pTrip = par_pos + "_" + ch1_b + "_" + ch2_pos;
	tmp = "FPOSS_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSS_TRIP=" + pTrip;
	}
	else{
		tmp = "AFPOSS_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pTrip = par_cpos + "_" + ch1_cb + "_" + ch2_cpos;
	tmp = "FCPOSS_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSS_TRIP=" + pTrip;
	}
	else{
		tmp = "AFCPOSS_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pTrip = par_pos + "_" + ch1_pos + "_" + ch2_b;
	tmp = "FPOST_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOST_TRIP=" + pTrip;
	}
	else{
		tmp = "AFPOST_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pTrip = par_cpos + "_" + ch1_cpos + "_" + ch2_cb;
	tmp = "FCPOST_TRIP=" + pTrip + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOST_TRIP=" + pTrip;
	}
	else{
		tmp = "AFCPOST_TRIP=" + pTrip;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe2O::addSiblingFeatures(DependencyInstance *instance, int ch1, int ch2, bool isST, FeatureVector *fv){
	vector<string*> *forms = instance->forms;
	vector<string*> *pos = instance->postags;
	vector<string*> *cpos = instance->cpostags;

	// ch1 is always the closes to par
	string dir = ch1 > ch2 ? "RA" : "LA";

	string ch1_pos = isST ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = (*(*pos)[ch2]);
	string ch1_cpos = isST ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = (*(*cpos)[ch2]);
	string ch1_word = isST ? "STWRD" : *(*forms)[ch1];
	string ch2_word = *(*forms)[ch2];

	bool flag;
	string tmp = "CH_PAIR=" + ch1_pos + "_" + ch2_pos + "_" + dir;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_CPAIR=" + ch1_cpos + "_" + ch2_cpos + "_" + dir;
	}
	else{
		tmp = "CH_CPAIR=" + ch1_cpos + "_" + ch2_cpos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_WPAIR=" + ch1_word + "_" + ch2_word + "_" + dir;
	}
	else{
		tmp = "CH_WPAIR=" + ch1_word + "_" + ch2_word + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_WPAIRA=" + ch1_word + "_" + ch2_pos + "_" + dir;
	}
	else{
		tmp = "CH_WPAIRA=" + ch1_word + "_" + ch2_pos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_WPAIRB=" + ch1_pos + "_" + ch2_word + "_" + dir;
	}
	else{
		tmp = "CH_WPAIRB=" + ch1_pos + "_" + ch2_word + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_WPAIRC=" + ch1_word + "_" + ch2_cpos + "_" + dir;
	}
	else{
		tmp = "CH_WPAIRC=" + ch1_word + "_" + ch2_cpos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_WPAIRD=" + ch1_cpos + "_" + ch2_word + "_" + dir;
	}
	else{
		tmp = "CH_WPAIRD=" + ch1_cpos + "_" + ch2_word + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_PAIR=" + ch1_pos + "_" + ch2_pos;
	}
	else{
		tmp = "ACH_PAIR=" + ch1_pos + "_" + ch2_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_CPAIR=" + ch1_cpos + "_" + ch2_cpos;
	}
	else{
		tmp = "ACH_CPAIR=" + ch1_cpos + "_" + ch2_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_WPAIR=" + ch1_word + "_" + ch2_word;
	}
	else{
		tmp = "ACH_WPAIR=" + ch1_word + "_" + ch2_word;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_WPAIRA=" + ch1_word + "_" + ch2_pos;
	}
	else{
		tmp = "ACH_WPAIRA=" + ch1_word + "_" + ch2_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_WPAIRB=" + ch1_pos + "_" + ch2_word;
	}
	else{
		tmp = "ACH_WPAIRB=" + ch1_pos + "_" + ch2_word;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_WPAIRC=" + ch1_word + "_" + ch2_cpos;
	}
	else{
		tmp = "ACH_WPAIRC=" + ch1_word + "_" + ch2_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_WPAIRD=" + ch1_cpos + "_" + ch2_word;
	}
	else{
		tmp = "ACH_WPAIRD=" + ch1_cpos + "_" + ch2_word;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	int dist = abs(ch1 - ch2);
	string distBool = "0";
	if (dist > 1){
		distBool = "1";
	}
	if (dist > 2){
		distBool = "2";
	}
	if (dist > 3){
		distBool = "3";
	}
	if (dist > 4){
		distBool = "4";
	}
	if (dist > 5){
		distBool = "5";
	}
	if (dist > 10){
		distBool = "10";
	}

	tmp = "SIB_PAIR_DIST=" + distBool + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ASIB_PAIR_DIST=" + distBool;
	}
	else{
		tmp = "ASIB_PAIR_DIST=" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_PAIR_DIST=" + ch1_pos + "_" + ch2_pos + "_" + distBool + "_" + dir;
	}
	else{
		tmp = "CH_PAIR_DIST=" + ch1_pos + "_" + ch2_pos + "_" + distBool + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_PAIR_DIST=" + ch1_pos + "_" + ch2_pos + "_" + distBool;
	}
	else{
		tmp = "ACH_PAIR_DIST=" + ch1_pos + "_" + ch2_pos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CH_CPAIR_DIST=" + ch1_cpos + "_" + ch2_cpos + "_" + distBool + "_" + dir;
	}
	else{
		tmp = "CH_CPAIR_DIST=" + ch1_cpos + "_" + ch2_cpos + "_" + distBool + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ACH_CPAIR_DIST=" + ch1_cpos + "_" + ch2_cpos + "_" + distBool;
	}
	else{
		tmp = "ACH_CPAIR_DIST=" + ch1_cpos + "_" + ch2_cpos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe2O::writeExtendedFeatures(DependencyInstance *instance, ObjectWriter &out){
	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector prodFV = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
				}
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}
	}
	out.writeInt(-3);
}

DependencyInstance* DependencyPipe2O::readInstance(ObjectReader &in, int length, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<double> > > &probs_grands, std::vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	// Get production crap.
	for (int w1 = 0; w1 < length; w1++) {
		for (int w2 = w1 + 1; w2 < length; w2++) {
			for (int ph = 0; ph < 2; ph++) {
				int *keys = NULL;
				int size = in.readArray(keys);
				probs[w1][w2][ph] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	int last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	if (labeled) {
		for (int w1 = 0; w1 < length; w1++) {
			int len = (int)(types.size());
			for (int t = 0; t < len; t++) {
				for (int ph = 0; ph < 2; ph++) {
					for (int ch = 0; ch < 2; ch++) {
						int *keys = NULL;
						int size = in.readArray(keys);
						nt_probs[w1][t][ph][ch] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
		last = in.readInt();
		if (last != -3) {
			cout<<"Error reading file."<<endl;
			exit(0);
		}
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = 0; w2 <length; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_sibs[w1][w2][wh] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				if(w3 == w2){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	int *keys = NULL;
	int size = in.readArray(keys);
	FeatureVector* nfv = new FeatureVector();
	nfv->construct(keys, size);
	delete[](keys);
	last = in.readInt();
	if (last != -4) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	DependencyInstance* marshalledDI = new DependencyInstance();
	marshalledDI->readObject(in);
	marshalledDI->setFeatureVector(nfv);

	last = in.readInt();
	if (last != -1) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}
	return marshalledDI;
}

void DependencyPipe2O::fillFeatureVectors(DependencyInstance *instance, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<double> > > &probs_grands, std::vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	((DependencyPipe*)this)->fillFeatureVectors(instance, probs, nt_probs, params);

	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
		for(int w2 = w1; w2 >= 0 ; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector fv = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &fv);
					double prodProb = params->getScore(&fv);
					probs_sibs[w1][w2][wh] = prodProb;
				}
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}
	}
}
